﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Transactions;
using Codeflows.Tracking;

namespace Codeflows.Extensions.Tracking
{
    static class CodeflowTrackerExtensions
    {
        static readonly TransactionOptions DefaultTransactionOptions = new TransactionOptions
                                                                           {
                                                                               IsolationLevel =
                                                                                   IsolationLevel.ReadCommitted
                                                                           };

        public static void Update(this ICodeflowTrackerFactory trackerFactory, CodeflowInstance codeflowInstance)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, DefaultTransactionOptions))
            {
                using (var tracker = trackerFactory.CreateTracker())
                {
                    tracker.Instance.Update(codeflowInstance);
                    scope.Complete();
                }
            }
        }

        public static IEnumerable<CodeflowInstance> ReadNextRunUpdate(this ICodeflowTrackerFactory trackerFactory,
                                                                      Action<CodeflowInstance> action, int count)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, DefaultTransactionOptions))
            {
                using (var tracker = trackerFactory.CreateTracker())
                {
                    IList<CodeflowInstance> instances = null;
                    ProfilingHelpers.ProfileAction(() => instances = tracker.Instance.ReadNext(count), "Read next batch");                    

                    if (!instances.Any())
                        return Enumerable.Empty<CodeflowInstance>();

                    foreach (var instance in instances)
                    {
                        action(instance);
                    }

                    ProfilingHelpers.ProfileAction(() =>
                    {
                        tracker.Instance.Update(instances);
                        scope.Complete();
                    }, "Update runnable batch.");
                    
                    return instances;
                }
            }
        }

        public static IEnumerable<CodeflowInstance> ForEachReadyInstance(this ICodeflowTrackerFactory trackerFactory,
                                                                         Action<CodeflowInstance> action, int count)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, DefaultTransactionOptions))
            {
                using (var tracker = trackerFactory.CreateTracker())
                {
                    IList<CodeflowInstance> instances = null;

                    ProfilingHelpers.ProfileAction(() => instances = tracker.Instance.ReadReadyList(count),
                                                   "Read ready list");

                    if (!instances.Any())
                        return Enumerable.Empty<CodeflowInstance>();

                    foreach (var instance in instances)
                    {
                        action(instance);
                    }

                    ProfilingHelpers.ProfileAction(() =>
                                                       {
                                                           tracker.Instance.Update(instances);
                                                           scope.Complete();
                                                       }, "Update ready instances");

                    return instances;
                }
            }
        }

        public static CodeflowInstance ReadRunUpdate(this ICodeflowTrackerFactory trackerFactory, Guid codeflowId,
                                                     Action<CodeflowInstance> action)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, DefaultTransactionOptions))
            {
                using (var tracker = trackerFactory.CreateTracker())
                {
                    var instance = tracker.Instance.Read(codeflowId);

                    action(instance);
                    tracker.Instance.Update(instance);
                    scope.Complete();
                    return instance;
                }
            }
        }
    }
}